跳到主要内容

1.3-声明文件

Create by fall on 13 Jan 2022 Recently revised in 11 Jul 2023

声明文件

TS 负责的是类型判断,对代码进行类型判断,然后解析为 JS 去执行。(TS 中,所有内容必须都有声明,否则报错)

注:默认存在一个 lib.d.ts 声明文件,以引入必要的声明。

环境声明

通过 declare 关键字来告诉 TypeScript 一个其他地方已经存在的代码。

// 在 main.ts 中使用在其他地方已经定义的变量
foo = 1123 // Error

我们需要使用 .d.ts 结尾的文件进行声明,一般会使用 global.d.ts 或者 vendor.d.ts

// global.d.ts
declare let foo:any
// main.ts
foo = 1123 // declare 声明了该变量,将不会报错

其他的声明文件的功能,也类似于该声明,但会更加详细,一般不需要自行书写。

非 JS 资源声明

在 ts 文件中,可能引入其他类型的文件,比如 png。为了避免报错,向文件中进行声明。

// index.d.ts
declare module '*.svg'
declare module '*.png'
declare module '*.vue'{ // 用于定义以 .vue 结尾的文件,并且让 typescript 跳过识别
import type {DefineComponent} from 'vue'
const component: DefineComponent <{}, {}, any>
export default component
}
// 在声明之后就可以使用
import * as foo from './some/file.css'

第三方 npm 包

当使用第三方库时,第三方库如果指明了声明文件,通过声明文件,能获得对应的代码补全、接口提示等功能。

但引入一个没有声明的 JS 库,ts 内使用使用的时候就会报错,此时需要查看是否有对应的 @types/package-name。有,使用 npm 安装即可;没有,自己手动声明。

安装声明库

# yarn
yarn add --dev @types/react
# npm
npm i --save-dev @types/react

手动声明 jquery

// 定义 global.d.ts
declare module 'jquery' {
// some variable declarations
export var bar: number;
}
// 导入使用 main.js
// 在必要的时候进行导入
import * as $ from 'jquery'
// import vue from 'vue' // 如果没有进行 declare 声明,直接引入会报错

在声明文件中,每个根级别的声明必须以 declare 关键字作为前缀, TypeScript 将不会把它编译成任何代码。

开发者需要确保这些声明文件,和声明的内容在编译时存在。

自定义 npm 包

如果你需要对自己的 npm 包制作声明文件,可以通过以下几个步骤实现:

  1. package.json 中的 types 或者 typings 属性添加环境声明路径,如:"types":"dist/typings/index.d.ts"
  2. 在项目根目录创建 typings 文件夹,新建一个 index.d.ts 用来暴露你 lib 库相关的声明
  3. typescript.json 配置文件中,添加入口,如:"includes":["./typings/index.d.ts"]

定义一个 index.d.ts,主要靠以下几个关键字:

  • export 导出变量
  • export namespace 导出(含有子属性的)对象
  • export default ES6 默认导出
  • export = commonjs 导出模块

PS: 只有只有 functionclassinterface 支持export default

示例:

// index.d.ts
// 将 src 中的声明文件引入过来
export * from '../src/index';
// 导出声明的函数
export declare function bar(): string;
// demo.js
// 使用就如下 bar就是一个函数
import { bar } from 'libs'
bar();

lib.d.ts

TS 默认添加,包含 JavaScript 浏览器各种原生 API 的声明。

在安装 typescript 时,同时会安装并且启用 lib.d.ts 声明文件,包含 JavaScript 浏览器各种原生的 API 声明。可以在 tsconfig.json 中指定 noLib:true 从上下文排除该文件,排除后如果没有自行添加声明,会报错。

改为自行添加声明可以在 TS 层面禁用部分浏览器的 API。

// example.js
const foo = 123;
const bar = foo.toString();
// 如果将 noLib:true,该代码就会出现类型检查错误

修改原生 API 的声明

如果要修改 lib.d.ts 中的内容,不建议在 lib.d.ts 中修改,而是自定义个全局模块(一般命名为 global.d.ts)然后在自定义模块的基础上添加内容。

如果一个模块没有 export(导出)功能,通常就是全局模块。

// 向全局变量 window 中添加方法
// global.d.ts
interface Window {
helloWorld(text:string):void
}
// 向脚本中添加该内容
// index.ts
window.helloWorld = (text: string) => ('妈妈咪呀,' + text)
window.helloWorld('kiss kiss')

一般来讲,interface 和 JS 中的对象名称保持一致,但有一些声明比较特殊

// 全局变量 Date
// lib.d.ts 中关于 Date 的声明是
declare var Date: DateConstructor
// 因此如果想在 Date 中添加新的方法,需要在 global.d.ts 中更改
interface DateConstructor{
now():string
}

全局模块

默认情况下,在一个新的 ts 文件中写代码时,它默认处于全局命名空间中

// foo.ts
const foo = 123
// 此时,如果在相同的项目里,创建一个新的文件 bar.ts 系统会允许你使用 foo 内的内容
// bar.ts
const back = foo

可以通过导入导出,避免暴露在全局作用域

// foo.ts
export const foo = 123
// 如果想继续使用 foo 就需要进行导入,并且使用其他变量也不会污染全局作用域
// bar.ts
import {foo} from './foo' // 此时还会将该文件定义为一个模块,文件内定义的变量也不会污染全局空间
const back = foo

声明空间和变量空间

TS 的声明内容都是只能在声明空间调用,而不是 JS 的变量空间

class Foo{}
type Bus = {}
interface Bar{}
// 这些变量空间的内容,都可以作为类型注解使用
let foo:Foo
let bus:Bus
let bar:Bar
// 但是 Bar 不能赋值,因为 Bar 只存在类型声明空间
const bar = Bar // error: cannot find name 'Bar'

变量声明空间

class Foo {}
const someVar = Foo
// class Foo {} Foo 既会被放置到变量声明空间,也会放到类型声明空间

命名空间

现在,TS 文件中使用 export 就可以表明该文件是一个模块,就拥有了独自的命名空间。

两种使用方式

  • export 导出,需要进行手动导入
  • declare 导出,直接声明全局文件

注:使用 export 之后,该文件就会变为块级作用域,在改文件中的任何 declare 和 export 的 namespace 都需要手动导入

// declare.d.ts
export namespace Tool{

}
// declare.d.ts
declare namespace Weapon{

}

.ts 结尾的文件中, ES2015 模块化优先于 namespace ,ESlint 会报错

引用命名空间

/// <reference path="xxx.ts" />
// 相当于导入 xxx.ts 文件的命名空间并和当前的命名空间进行合并
import { Lee } from "./xxx";
// 从文件 xxx 中引入命名空间 Lee

参考文章

作者文章名称
jkchao深入理解TypeScript
铁皮饭盒https://juejin.cn/post/6844903993727008776
铁皮饭盒https://juejin.cn/post/6844903921031479309
QBorfyTypescript 基础:如何更好的生成 Typescript 声明文件.d.ts